﻿using IMAPI2.Interop;
using IMAPI2.MediaItem;
using PSDClientService.SystemSettings;
using PSDLib.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PSDClientService.Burn
{
    public class BurnDeviceManager_expired
    {

        public delegate void GetRecordingDeviceEvnetHandler(RecorderDevice recorder);
        public event GetRecordingDeviceEvnetHandler OnGetRecordingDevice;

        public event UpdateCapacityEventHandler OnUpdateCapacity;
        public event BurnProgressEventHandler OnBurnProgress;
        public event BurnSuccessEventhandler OnBurnSuccess;
        public event BurnErrorEventHandler OnBurnError;
        public event DetectRecorderEventHandler OnDetectRecorder;

        private BurnContext context;

        public List<RecorderDevice> RecorderList { get; set; }

        private Semaphore DeviceSemaphore { get; set; }

        public BurnDeviceManager_expired(BurnContext ctx)
        {
            context = ctx;

            RecorderList = new List<RecorderDevice>();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public bool Init()
        {
            bool success = false;

            DeviceSemaphore = new Semaphore(AppSettings.Setting.RecorderCount, AppSettings.Setting.RecorderCount);

            success = GetRecordingDevice();

            return success;
        }

        /// <summary>
        /// 获取所有刻录设备
        /// </summary>
        /// <returns></returns>
        private bool GetRecordingDevice()
        {
            bool success = false;
            //
            // Determine the current recording devices
            //
            MsftDiscMaster2 discMaster = null;
            try
            {
                context.Logger.Info("Init Recorder Device");

                discMaster = new MsftDiscMaster2();

                if (!discMaster.IsSupportedEnvironment)
                {
                    context.Logger.Error("设备不支持刻录功能");
                    return false;
                }

                foreach (string uniqueRecorderId in discMaster)
                {
                    var recorder = new RecorderDevice(context, uniqueRecorderId);
                    recorder.OnBurnProgress += Recoder_OnBurnProgress;
                    recorder.OnBurnSuccess += Recoder_OnBurnSuccess;
                    recorder.OnBurnError += Recoder_OnBurnError;
                    recorder.OnDetectRecorder += Recorder_OnDetectRecorder;
                    recorder.OnUpdateCapacity += Recorder_OnUpdateCapacity;
                    RecorderList.Add(recorder);

                    OnGetRecordingDevice?.Invoke(recorder);

                    context.Logger.Log($"{RecorderList.Count}.{recorder.RecorderId} - {recorder.VolumePathName}[{recorder.ProductId}]");
                }

                success = true;
            }
            catch (COMException ex)
            {
                context.Logger.Error(string.Format("BurnManager Init Error:{0} - Please install IMAPI2", ex.ErrorCode));
                success = false;
            }
            finally
            {
                if (discMaster != null)
                {
                    Marshal.ReleaseComObject(discMaster);
                }
            }

            //success = UpdateCapacity();

            return success;
        }

        private void Recorder_OnUpdateCapacity(RecorderDevice device, long totalDiscSize, long totalMediaSize)
        {
            OnUpdateCapacity?.Invoke(device, totalDiscSize, totalMediaSize);
        }

        private void Recorder_OnDetectRecorder(RecorderDevice device, bool success, string info)
        {
            OnDetectRecorder?.Invoke(device, success, info);
        }

        private void Recoder_OnBurnError(RecorderDevice device, BurnJob burningDVD, string info)
        {
            OnBurnError?.Invoke(device, burningDVD, info);

            ReleaseDevice();
        }

        private void Recoder_OnBurnSuccess(RecorderDevice device, BurnJob burningDVD, string info)
        {
            OnBurnSuccess?.Invoke(device, burningDVD, info);

            ReleaseDevice();
        }

        private void Recoder_OnBurnProgress(RecorderDevice device, BurnJob burningDVD, string info, int percent)
        {
            OnBurnProgress?.Invoke(device, burningDVD, info, percent);
        }

        /// <summary>
        /// 获取当前可用的刻录设备
        /// </summary>
        /// <returns></returns>
        public RecorderDevice GetStandbyDevice()
        {
            if (WaitDevice())
            {
                var device = RecorderList.Where(t => t.State == RecorderState.Standby).FirstOrDefault();

                if (device != null && SetCurrentRecorder(device))
                {
                    device.State = RecorderState.Burning;

                    return device;
                }
                else
                {
                    return null;
                }
            }

            return null;
        }

        /// <summary>
        /// 等待直到获得一个可用设备信号量
        /// </summary>
        public bool WaitDevice()
        {
            return DeviceSemaphore.WaitOne();
        }

        /// <summary>
        /// 释放一个可用设备信号量
        /// </summary>
        public void ReleaseDevice()
        {
            DeviceSemaphore.Release();
        }

        /// <summary>
        /// 设置要使用的刻录设备
        /// </summary>
        /// <param name="discRecorder"></param>
        public bool SetCurrentRecorder(RecorderDevice device)
        {
            //
            // Verify recorder is supported
            //

            bool success = false;
            IDiscFormat2Data discFormatData = null;
            try
            {
                discFormatData = new MsftDiscFormat2Data();
                if (!discFormatData.IsRecorderSupported(device.Recorder))
                {
                    //MessageBox.Show("不被支持的刻录设备", "提示",
                    //    MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }

                StringBuilder supportedMediaTypes = new StringBuilder();
                foreach (IMAPI_PROFILE_TYPE profileType in device.Recorder.SupportedProfiles)
                {
                    string profileName = GetProfileTypeString(profileType);

                    if (string.IsNullOrEmpty(profileName))
                        continue;

                    if (supportedMediaTypes.Length > 0)
                        supportedMediaTypes.Append(", ");
                    supportedMediaTypes.Append(profileName);
                }

                success = device.DetectRecorder();
                //supportedMediaLabel.Text = supportedMediaTypes.ToString();
            }
            catch (COMException)
            {
                success = false;
                //supportedMediaLabel.Text = "Error getting supported types";
            }
            finally
            {
                if (discFormatData != null)
                {
                    Marshal.ReleaseComObject(discFormatData);
                }
            }

            return success;
        }



        static string GetProfileTypeString(IMAPI_PROFILE_TYPE profileType)
        {
            switch (profileType)
            {
                default:
                    return string.Empty;

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_CD_RECORDABLE:
                    return "CD-R";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_CD_REWRITABLE:
                    return "CD-RW";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVDROM:
                    return "DVD ROM";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_DASH_RECORDABLE:
                    return "DVD-R";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_RAM:
                    return "DVD-RAM";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_PLUS_R:
                    return "DVD+R";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_PLUS_RW:
                    return "DVD+RW";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_PLUS_R_DUAL:
                    return "DVD+R Dual Layer";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_DASH_REWRITABLE:
                    return "DVD-RW";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_DASH_RW_SEQUENTIAL:
                    return "DVD-RW Sequential";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_DASH_R_DUAL_SEQUENTIAL:
                    return "DVD-R DL Sequential";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_DASH_R_DUAL_LAYER_JUMP:
                    return "DVD-R Dual Layer";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_DVD_PLUS_RW_DUAL:
                    return "DVD+RW DL";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_HD_DVD_ROM:
                    return "HD DVD-ROM";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_HD_DVD_RECORDABLE:
                    return "HD DVD-R";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_HD_DVD_RAM:
                    return "HD DVD-RAM";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_BD_ROM:
                    return "Blu-ray DVD (BD-ROM)";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_BD_R_SEQUENTIAL:
                    return "Blu-ray media Sequential";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_BD_R_RANDOM_RECORDING:
                    return "Blu-ray media";

                case IMAPI_PROFILE_TYPE.IMAPI_PROFILE_TYPE_BD_REWRITABLE:
                    return "Blu-ray Rewritable media";
            }
        }
    }
}
